package service

import (
	"context"
	"encoding/json"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	app2 "github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
	"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
	"go.uber.org/zap"
	"mall-portalv2/conf"
	"mall-portalv2/global"
	"mall-portalv2/internal/model"
	"time"
)

var (
	mchID                      string = conf.Config.WechatPay.MchID                      // 商户号
	mchCertificateSerialNumber string = conf.Config.WechatPay.MchCertificateSerialNumber // 商户证书序列号
	mchAPIv3Key                string = conf.Config.WechatPay.MchAPIv3Key                // 商户APIv3密钥
)

type WechatPay struct {
	MchID                      string
	MchCertificateSerialNumber string
	MchAPIv3Key                string
}

type WechatCallBackData struct {
	Mchid          string    `json:"mchid"`
	Appid          string    `json:"appid"`
	OutTradeNo     string    `json:"out_trade_no"`
	TransactionId  string    `json:"transaction_id"`
	TradeType      string    `json:"trade_type"`
	TradeState     string    `json:"trade_state"`
	TradeStateDesc string    `json:"trade_state_desc"`
	BankType       string    `json:"bank_type"`
	Attach         string    `json:"attach"`
	SuccessTime    time.Time `json:"success_time"`
	Payer          struct {
		Openid string `json:"openid"`
	} `json:"payer"`
	Amount struct {
		Total         int64  `json:"total"`
		PayerTotal    int64  `json:"payer_total"`
		Currency      string `json:"currency"`
		PayerCurrency string `json:"payer_currency"`
	} `json:"amount"`
}

type ReturnSuccessExample struct {
	RefundId            string    `json:"refund_id"`
	OutRefundNo         string    `json:"out_refund_no"`
	TransactionId       string    `json:"transaction_id"`
	OutTradeNo          string    `json:"out_trade_no"`
	Channel             string    `json:"channel"`
	UserReceivedAccount string    `json:"user_received_account"`
	SuccessTime         time.Time `json:"success_time"`
	CreateTime          time.Time `json:"create_time"`
	Status              string    `json:"status"`
	FundsAccount        string    `json:"funds_account"`
	Amount              struct {
		Total  int `json:"total"`
		Refund int `json:"refund"`
		From   []struct {
			Account string `json:"account"`
			Amount  int    `json:"amount"`
		} `json:"from"`
		PayerTotal       int    `json:"payer_total"`
		PayerRefund      int    `json:"payer_refund"`
		SettlementRefund int    `json:"settlement_refund"`
		SettlementTotal  int    `json:"settlement_total"`
		DiscountRefund   int    `json:"discount_refund"`
		Currency         string `json:"currency"`
	} `json:"amount"`
	PromotionDetail []struct {
		PromotionId  string `json:"promotion_id"`
		Scope        string `json:"scope"`
		Type         string `json:"type"`
		Amount       int    `json:"amount"`
		RefundAmount int    `json:"refund_amount"`
		GoodsDetail  []struct {
			MerchantGoodsId  string `json:"merchant_goods_id"`
			WechatpayGoodsId string `json:"wechatpay_goods_id"`
			GoodsName        string `json:"goods_name"`
			UnitPrice        int    `json:"unit_price"`
			RefundAmount     int    `json:"refund_amount"`
			RefundQuantity   int    `json:"refund_quantity"`
		} `json:"goods_detail"`
	} `json:"promotion_detail"`
}

func (wechatPay *WechatPay) initClient() (*core.Client, error) {

	var (
		client *core.Client
		err    error
	)

	global.Log.Info("打印一下client的数据", zap.Any("wechatPay", wechatPay))

	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath(conf.Config.WechatPay.PrivateKeyPath)
	if err != nil {
		global.Log.Error("请求参数不正确", zap.Error(err))
		return client, err
	}

	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(wechatPay.MchID, wechatPay.MchCertificateSerialNumber, mchPrivateKey, wechatPay.MchAPIv3Key),
	}

	contextWx := context.Background()

	client, err = core.NewClient(contextWx, opts...)
	if err != nil {
		global.Log.Error("请求参数不正确", zap.Error(err))
		return client, err
	}
	return client, nil
}

func (s *Service) WechatPay(ctx context.Context, Order model.OmsOrder, TimeExpire time.Time, allPrice float64, paySn string) (*app2.PrepayWithRequestPaymentResponse, error) {

	var wechatPay = WechatPay{
		MchID:                      conf.Config.WechatPay.MchID,
		MchCertificateSerialNumber: conf.Config.WechatPay.MchCertificateSerialNumber,
		MchAPIv3Key:                conf.Config.WechatPay.MchAPIv3Key,
	}

	wechatClient, err := wechatPay.initClient()
	if err != nil {
		global.Log.Error("微信客户端初始化失败", zap.Error(err))
		return nil, err
	}

	// 发送请求
	wechatSvc := app2.AppApiService{Client: wechatClient}
	resp, _, err := wechatSvc.PrepayWithRequestPayment(ctx,
		app2.PrepayRequest{
			Appid:       core.String(conf.Config.WechatPay.Appid),
			Mchid:       core.String(wechatPay.MchID),
			Description: core.String(Order.PromotionInfo),
			OutTradeNo:  core.String(paySn),
			TimeExpire:  core.Time(TimeExpire),
			Attach:      core.String("众筹商品"),
			NotifyUrl:   core.String(conf.Config.WechatPay.NotifyUrl),
			GoodsTag:    core.String("test"),
			//LimitPay:      []string{"LimitPay_example"},
			SupportFapiao: core.Bool(false),
			Amount: &app2.Amount{
				Currency: core.String("CNY"),
				Total:    core.Int64(int64(allPrice * 100)),
			},
		},
	)
	//resp, result, err := svc.DownloadCertificates(context.Background())
	//log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
	if err != nil {
		global.Log.Error("请求参数不正确", zap.Error(err))
		return nil, err
	}

	global.Log.Info("wchatPay", zap.Any("resp", resp), zap.Any("订单编号", Order.OrderSn))

	if err != nil {
		global.Log.Error("请求参数不正确", zap.Error(err))
		return nil, err
	}

	return resp, nil
}

func (s *Service) WechatTradeRefund(ctx context.Context, Order model.OmsOrder, data model.TradeRefundData, price float64) error {

	wechatCallBackData := WechatCallBackData{}

	if err := json.Unmarshal([]byte(Order.PaymentData), &wechatCallBackData); err != nil {
		global.Log.Error("回调信息解析错误", zap.Error(err))
		return err
	}

	var wechatPay = WechatPay{
		MchID:                      conf.Config.WechatPay.MchID,
		MchCertificateSerialNumber: conf.Config.WechatPay.MchCertificateSerialNumber,
		MchAPIv3Key:                conf.Config.WechatPay.MchAPIv3Key,
	}

	wechatClient, err := wechatPay.initClient()
	if err != nil {
		global.Log.Error("微信客户端初始化失败", zap.Error(err))
		return err
	}
	global.Log.Info("打印一下要退款的金额", zap.Any("price", price))

	// TODO: 查询对应的流水号
	//Order.ID
	PayLogs, err := s.QueryPayLogsWhereOrderIdAndPaySnNoWay(ctx, Order.ID, wechatCallBackData.OutTradeNo)
	if err != nil {
		global.Log.Error("退款查询流水号失败", zap.Error(err))
		return err
	}

	global.Log.Info("打印流水号", zap.Any("PayLogs", PayLogs.PaySn))

	// 发送请求
	wechatSvc := refunddomestic.RefundsApiService{Client: wechatClient}
	resp, result, err := wechatSvc.Create(ctx,
		refunddomestic.CreateRequest{
			//SubMchid:      core.String(wechatPay.MchID),
			TransactionId: core.String(wechatCallBackData.TransactionId),
			OutTradeNo:    core.String(PayLogs.PaySn),
			OutRefundNo:   core.String(data.ReturnSn),
			Reason:        core.String("用户退款"),
			NotifyUrl:     core.String(conf.Config.WechatPay.NotifyUrl),
			FundsAccount:  refunddomestic.REQFUNDSACCOUNT_AVAILABLE.Ptr(),
			Amount: &refunddomestic.AmountReq{
				Currency: core.String("CNY"),
				//From: []refunddomestic.FundsFromItem{
				//	refunddomestic.FundsFromItem{
				//		Account: refunddomestic.ACCOUNT_AVAILABLE.Ptr(),
				//		Amount:  core.Int64(1),
				//	}},
				Refund: core.Int64(int64(price * 100)),
				Total:  core.Int64(wechatCallBackData.Amount.Total),
			},
			//GoodsDetail: []refunddomestic.GoodsDetail{refunddomestic.GoodsDetail{
			//	GoodsName:        core.String("iPhone6s 16G"),
			//	MerchantGoodsId:  core.String("1217752501201407033233368018"),
			//	RefundAmount:     core.Int64(528800),
			//	RefundQuantity:   core.Int64(1),
			//	UnitPrice:        core.Int64(528800),
			//	WechatpayGoodsId: core.String("1001"),
			//}},
		},
	)
	global.Log.Info("打印一下微信退款的信息返回", zap.Any("status", result.Response.StatusCode), zap.Any("resp", resp), zap.Any("result", result))
	if err != nil {
		global.Log.Error("请求参数不正确", zap.Error(err))
		return err
	}

	// TODO: 修改对应的退款记录
	if result.Response.StatusCode != 200 {
		global.Log.Error("微信返回请求参数不正确", zap.Error(err))
		return err
	}

	return nil
}

func (s *Service) WechatClose(ctx context.Context, Order model.OmsOrder, TradeNo string) error {

	// 订单状态：0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭；5->无效订单

	//TradeNo := ""
	//if Order.Status == 0 {
	//	TradeNo = Order.OrderSn
	//} else {
	//	wechatCallBackData := WechatCallBackData{}
	//
	//	if err := json.Unmarshal([]byte(Order.PaymentData), &wechatCallBackData); err != nil {
	//		global.Log.Error("回调信息解析错误", zap.Error(err))
	//		return err
	//	}
	//
	//	TradeNo = wechatCallBackData.OutTradeNo
	//}

	var wechatPay = WechatPay{
		MchID:                      conf.Config.WechatPay.MchID,
		MchCertificateSerialNumber: conf.Config.WechatPay.MchCertificateSerialNumber,
		MchAPIv3Key:                conf.Config.WechatPay.MchAPIv3Key,
	}

	wechatClient, err := wechatPay.initClient()
	if err != nil {
		global.Log.Error("微信客户端初始化失败", zap.Error(err))
		return err
	}

	// 发送请求
	wechatSvc := app2.AppApiService{Client: wechatClient}
	result, err := wechatSvc.CloseOrder(ctx,
		app2.CloseOrderRequest{
			OutTradeNo: core.String(TradeNo),
			Mchid:      core.String(conf.Config.WechatPay.MchID),
		},
	)
	if err != nil {
		global.Log.Error("请求参数不正确", zap.Error(err))
		return err
	}
	global.Log.Info("打印一下微信关闭订单的信息返回", zap.Any("result", result.Response.StatusCode))

	return nil
}
